﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using l1cs.server.model.Instance;
using l1cs.server.model.skill;
using l1cs.server.serverpackets;
using l1cs.server.datatables;
using l1cs.server.templates;
using l1cs.server.utils;

namespace l1cs.server.model
{
    public abstract class L1ArmorSet
    {
        public abstract void giveEffect( L1PcInstance pc );

        public abstract void cancelEffect( L1PcInstance pc );

        public abstract bool isValid( L1PcInstance pc );

        public abstract bool isPartOfSet( int id );

        public abstract bool isEquippedRingOfArmorSet( L1PcInstance pc );

        public static List<L1ArmorSet> getAllSet()
        {
            return _allSet;
        }

        private static List<L1ArmorSet> _allSet = new List<L1ArmorSet>();

        /*
         * ここで初期化してしまうのはいかがなものか・・・美しくない気がする
         */
        static L1ArmorSet()
        {
            L1ArmorSetImpl impl;

            foreach ( L1ArmorSets armorSets in ArmorSetTable.getInstance().getAllList() )
            {

                impl = new L1ArmorSetImpl( getArray( armorSets.getSets(), "," ) );
                if ( armorSets.getPolyId() != -1 )
                {
                    impl.addEffect( new PolymorphEffect( armorSets.getPolyId() ) );
                }
                impl.addEffect( new AcHpMpBonusEffect( armorSets.getAc(),
                        armorSets.getHp(), armorSets.getMp(),
                        armorSets.getHpr(), armorSets.getMpr(),
                        armorSets.getMr() ) );
                impl.addEffect( new StatBonusEffect( armorSets.getStr(),
                        armorSets.getDex(), armorSets.getCon(),
                        armorSets.getWis(), armorSets.getCha(),
                        armorSets.getIntl() ) );
                impl.addEffect( new DefenseBonusEffect( armorSets
                        .getDefenseWater(), armorSets.getDefenseWind(),
                        armorSets.getDefenseFire(), armorSets.getDefenseWind() ) );
                _allSet.Add( impl );

            }
        }

        private static int[] getArray( String s, String sToken )
        {
            StringTokenizer st = new StringTokenizer( s, new String[] { sToken } );
            int size = st.countTokens();
            String temp = null;
            int[] array = new int[size];
            for ( int i = 0; i < size; i++ )
            {
                temp = st.nextToken();
                array[i] = SqlUtils.toInt( temp );
            }
            return array;
        }
    }

    public interface L1ArmorSetEffect
    {
        void giveEffect( L1PcInstance pc );

        void cancelEffect( L1PcInstance pc );
    }

    class L1ArmorSetImpl : L1ArmorSet
    {
        private int[] _ids;
        private List<L1ArmorSetEffect> _effects;
        private static Logger _log = Logger.getLogger( typeof( L1ArmorSetImpl ).FullName );

        public L1ArmorSetImpl( int[] ids )
        {
            _ids = ids;
            _effects = new List<L1ArmorSetEffect>();
        }

        public void addEffect( L1ArmorSetEffect effect )
        {
            _effects.Add( effect );
        }

        public void removeEffect( L1ArmorSetEffect effect )
        {
            _effects.Remove( effect );
        }

        override public void cancelEffect( L1PcInstance pc )
        {
            foreach ( L1ArmorSetEffect effect in _effects )
            {
                effect.cancelEffect( pc );
            }
        }

        override public void giveEffect( L1PcInstance pc )
        {
            foreach ( L1ArmorSetEffect effect in _effects )
            {
                effect.giveEffect( pc );
            }
        }

        override public bool isValid( L1PcInstance pc )
        {
            return pc.getInventory().checkEquipped( _ids );
        }

        override public bool isPartOfSet( int id )
        {
            foreach ( int i in _ids )
            {
                if ( id == i )
                {
                    return true;
                }
            }
            return false;
        }

        override
        public bool isEquippedRingOfArmorSet( L1PcInstance pc )
        {
            L1PcInventory pcInventory = pc.getInventory();
            L1ItemInstance armor = null;
            bool isSetContainRing = false;

            // セット装備にリングが含まれているか調べる
            foreach ( int id in _ids )
            {
                armor = pcInventory.findItemId( id );
                if ( armor.getItem().getType2() == 2
                        && armor.getItem().getType() == 9 )
                { // ring
                    isSetContainRing = true;
                    break;
                }
            }

            // リングを2つ装備していて、それが両方セット装備か調べる
            if ( armor != null && isSetContainRing )
            {
                int itemId = armor.getItem().getItemId();
                if ( pcInventory.getTypeEquipped( 2, 9 ) == 2 )
                {
                    L1ItemInstance[] ring = new L1ItemInstance[2];
                    ring = pcInventory.getRingEquipped();
                    if ( ring[0].getItem().getItemId() == itemId
                            && ring[1].getItem().getItemId() == itemId )
                    {
                        return true;
                    }
                }
            }
            return false;
        }

    }

    class AcHpMpBonusEffect : L1ArmorSetEffect
    {
        private int _ac;
        private int _addHp;
        private int _addMp;
        private int _regenHp;
        private int _regenMp;
        private int _addMr;

        public AcHpMpBonusEffect( int ac, int addHp, int addMp, int regenHp,
                int regenMp, int addMr )
        {
            _ac = ac;
            _addHp = addHp;
            _addMp = addMp;
            _regenHp = regenHp;
            _regenMp = regenMp;
            _addMr = addMr;
        }

        public void giveEffect( L1PcInstance pc )
        {
            pc.addAc( _ac );
            pc.addMaxHp( _addHp );
            pc.addMaxMp( _addMp );
            pc.addHpr( _regenHp );
            pc.addMpr( _regenMp );
            pc.addMr( _addMr );
        }

        public void cancelEffect( L1PcInstance pc )
        {
            pc.addAc( -_ac );
            pc.addMaxHp( -_addHp );
            pc.addMaxMp( -_addMp );
            pc.addHpr( -_regenHp );
            pc.addMpr( -_regenMp );
            pc.addMr( -_addMr );
        }
    }

    class StatBonusEffect : L1ArmorSetEffect
    {
        private int _str;
        private int _dex;
        private int _con;
        private int _wis;
        private int _cha;
        private int _intl;

        public StatBonusEffect( int str, int dex, int con, int wis, int cha, int intl )
        {
            _str = str;
            _dex = dex;
            _con = con;
            _wis = wis;
            _cha = cha;
            _intl = intl;
        }

        public void giveEffect( L1PcInstance pc )
        {
            pc.addStr( (byte)_str );
            pc.addDex( (byte)_dex );
            pc.addCon( (byte)_con );
            pc.addWis( (byte)_wis );
            pc.addCha( (byte)_cha );
            pc.addInt( (byte)_intl );
        }

        public void cancelEffect( L1PcInstance pc )
        {
            pc.addStr( (byte)-_str );
            pc.addDex( (byte)-_dex );
            pc.addCon( (byte)-_con );
            pc.addWis( (byte)-_wis );
            pc.addCha( (byte)-_cha );
            pc.addInt( (byte)-_intl );
        }
    }

    class DefenseBonusEffect : L1ArmorSetEffect
    {
        private int _defenseWater;
        private int _defenseWind;
        private int _defenseFire;
        private int _defenseEarth;

        public DefenseBonusEffect( int defenseWater, int defenseWind, int defenseFire, int defenseEarth )
        {
            _defenseWater = defenseWater;
            _defenseWind = defenseWind;
            _defenseFire = defenseFire;
            _defenseEarth = defenseEarth;
        }

        public void giveEffect( L1PcInstance pc )
        {
            pc.addWater( _defenseWater );
            pc.addWind( _defenseWind );
            pc.addFire( _defenseFire );
            pc.addEarth( _defenseEarth );
        }

        public void cancelEffect( L1PcInstance pc )
        {
            pc.addWater( -_defenseWater );
            pc.addWind( -_defenseWind );
            pc.addFire( -_defenseFire );
            pc.addEarth( -_defenseEarth );
        }
    }

    class PolymorphEffect : L1ArmorSetEffect
    {
        private int _gfxId;

        public PolymorphEffect( int gfxId )
        {
            _gfxId = gfxId;
        }

        public void giveEffect( L1PcInstance pc )
        {
            int awakeSkillId = pc.getAwakeSkillId();
            if ( awakeSkillId == L1SkillId.AWAKEN_ANTHARAS
                    || awakeSkillId == L1SkillId.AWAKEN_FAFURION
                    || awakeSkillId == L1SkillId.AWAKEN_VALAKAS )
            {
                pc.sendPackets( new S_ServerMessage( 1384 ) ); // 現在の状態では変身できません。
                return;
            }
            if ( _gfxId == 6080 || _gfxId == 6094 )
            {
                if ( pc.get_sex() == 0 )
                {
                    _gfxId = 6094;
                }
                else
                {
                    _gfxId = 6080;
                }
                if ( !isRemainderOfCharge( pc ) )
                { // 残チャージ数なし
                    return;
                }
            }
            L1PolyMorph.doPoly( pc, _gfxId, 0, L1PolyMorph.MORPH_BY_ITEMMAGIC );
        }

        public void cancelEffect( L1PcInstance pc )
        {
            int awakeSkillId = pc.getAwakeSkillId();
            if ( awakeSkillId == L1SkillId.AWAKEN_ANTHARAS
                    || awakeSkillId == L1SkillId.AWAKEN_FAFURION
                    || awakeSkillId == L1SkillId.AWAKEN_VALAKAS )
            {
                pc.sendPackets( new S_ServerMessage( 1384 ) ); // 現在の状態では変身できません。
                return;
            }
            if ( _gfxId == 6080 )
            {
                if ( pc.get_sex() == 0 )
                {
                    _gfxId = 6094;
                }
            }
            if ( pc.getTempCharGfx() != _gfxId )
            {
                return;
            }
            L1PolyMorph.undoPoly( pc );
        }

        private bool isRemainderOfCharge( L1PcInstance pc )
        {
            bool isRemainderOfCharge = false;
            if ( pc.getInventory().checkItem( 20383, 1 ) )
            {
                L1ItemInstance item = pc.getInventory().findItemId( 20383 );
                if ( item != null )
                {
                    if ( item.getChargeCount() != 0 )
                    {
                        isRemainderOfCharge = true;
                    }
                }
            }
            return isRemainderOfCharge;
        }
    }
}
